package cn.dansj.service.Impl;

import cn.dansj.entity.Role;
import cn.dansj.enums.GlobalEnv;
import cn.dansj.repository.RoleRepository;
import cn.dansj.service.RoleService;
import cn.dansj.common.jdbc.JpaUtil;
import cn.dansj.common.utils.transfer.GetTime;
import cn.dansj.common.utils.transfer.Transformation;
import cn.dansj.common.utils.transfer.RandomUtils;
import cn.dansj.common.utils.transfer.Verification;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import jakarta.persistence.criteria.Expression;
import jakarta.persistence.criteria.Predicate;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Service
public class RoleServiceImpl implements RoleService {
    private final RoleRepository roleRepository;

    public RoleServiceImpl(RoleRepository roleRepository) {
        this.roleRepository = roleRepository;
    }

    public List<Role> getAll() {
        return roleRepository.findAll(Sort.by(Sort.Direction.DESC, "sequence"));
    }

    public Page<Role> search(Integer pageNum,
                             Integer pageLimit,
                             String name,
                             String description,
                             String status) {
        Sort sort = Sort.by(Sort.Direction.DESC, "sequence");
        Pageable pageable = PageRequest.of(pageNum - 1, pageLimit, sort);
        Specification<Role> specification = (root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicateList = new ArrayList<>();
            if (Verification.checkNotNull(name)) {
                Expression<String> nameExpr = criteriaBuilder.lower(root.get("name").as(String.class));
                predicateList.add(criteriaBuilder.like(nameExpr, Transformation.sqlLikeToLowCase(name)));
            }
            if (Verification.checkNotNull(description)) {
                Expression<String> descExpr = criteriaBuilder.lower(root.get("description").as(String.class));
                predicateList.add(criteriaBuilder.like(descExpr, Transformation.sqlLikeToLowCase(description)));
            }
            if (Verification.checkNotNull(status)) {
                predicateList.add(criteriaBuilder.equal(root.get("status"), status));
            }
            Predicate[] predicates = new Predicate[predicateList.size()];
            return criteriaBuilder.and(predicateList.toArray(predicates));
        };

        return roleRepository.findAll(specification, pageable);
    }

    public void updateRole(Role role) {
        Optional.of(roleRepository.findById(role.getSequence())
                .orElseGet(() -> roleRepository.save(role))).map(entity -> {

            // 使用JpaUtil优雅的写法
            JpaUtil.copyNotNullProperties(role, entity);
            entity.setUpdateTime(GetTime.dbTimestamp());

            return roleRepository.save(entity);
        }).orElseGet(() -> roleRepository.save(role));
    }

    @Transactional
    public void updateStatus(String sequence) {
        Role role = roleRepository.findBySequence(sequence);
        String status;
        if ("1".equals(role.getStatus())) {
            status = "0";
        } else {
            status = "1";
        }
        roleRepository.updateStatus(sequence, status, GetTime.dbTimestamp());
    }

    @Transactional
    public void updateVip(String sequence) {
        Role role = roleRepository.findBySequence(sequence);
        int vip;
        if (role.getInterfaceVip() == 1) {
            vip = 0;
        } else {
            vip = 1;
        }
        roleRepository.updateVip(sequence, vip, GetTime.dbTimestamp());
    }

    public Role getRoleByName(String name) {
        return roleRepository.findByName(name);
    }

    @Override
    public boolean initRole() {
        Role superAdmin = roleRepository.findByName(GlobalEnv.SuperAdmin);
        List<Role> addRoles = new ArrayList<>();
        if (superAdmin == null) {
            Role role = new Role();
            role.setSequence(RandomUtils.sequence());
            role.setName(GlobalEnv.SuperAdmin);
            role.setDescription("超级管理员");
            role.setStatus("1");
            role.setCreator("System init");
            Timestamp now = new Timestamp(System.currentTimeMillis());
            role.setCrtTime(now);
            role.setUpdateTime(now);
            addRoles.add(role);
        }

        Role normal = roleRepository.findByName(GlobalEnv.Normal);
        if (normal == null) {
            Role role = new Role();
            role.setSequence(RandomUtils.sequence());
            role.setName(GlobalEnv.Normal);
            role.setDescription("base user");
            role.setStatus("1");
            role.setCreator("System init");
            Timestamp now = new Timestamp(System.currentTimeMillis());
            role.setCrtTime(now);
            role.setUpdateTime(now);
            addRoles.add(role);
        }

        if (Verification.checkNotNull(addRoles)) {
            try {
                roleRepository.saveAll(addRoles);
                return true;
            } catch (Exception exception) {
                return false;
            }
        }
        return true;
    }

    @Override
    public List<String> getInterfaceVip() {
        return roleRepository.getInterfaceVip();
    }
}
